package main;

import gui.RunningView;

import java.util.Random;

import mutation.MutationManager;

public abstract class GAabstruct implements GAinterface {
	public static final boolean debug = true;
	protected final boolean SHOW_BEST_IN_GUI = true;
	// private GUIGrid guiGrid;
	// private GUIGrid bestguiGrid;
	protected RunningView gui;

	protected boolean isFirstInit;
	/** The id for the run */
	protected String id;

	// Data per generation
	/** The best energy. */
	protected float[] bestEnergy;

	/** The best fitness. */
	protected float[] bestFitness;

	/** The average energy. */
	protected float[] averageEnergy;

	/** The average fitness. */
	protected float[] averageFitness;

	/** The worst energy. */
	protected float[] worstEnergy;

	/** The worst fitness. */
	protected float[] worstFitness;

	public int[] getGeneration() {
		return generation;
	}

	protected int generation[];

	/** The fittest per generation */
	protected Conformation[] fittest;

	// Data for All the Run
	/** The protein population. */
	protected Population population;

	/** The mutation manager. */
	protected MutationManager mutationManager;

	/** The current generarion num. */
	protected int currentGenerarionNum;

	/** The random number for usage in the run. */
	protected Random random;

	/** the output file writer. */
	protected OutputFilesWriter fileWriter;

	/** The configuration class to get User given arguments. */
	protected Configuration config;

	protected int numberOfGenerations, reportEvery;
	protected Protein bestProtein;

	/**
	 * 
	 * 
	 * Instantiates a new Genetic Algorithm (GA) run.
	 * 
	 * @param fileWriter
	 *            the file writer to write the stored data in the run
	 * @param config
	 *            the configuration object to load user given data
	 * 
	 */

	public GAabstruct(OutputFilesWriter fileWriter, Configuration config,
			MutationManager mutationManager) {

		this.config = config;
		this.random = config.random;
		this.fileWriter = fileWriter;
		this.mutationManager = mutationManager;
		isFirstInit = true;
		this.numberOfGenerations = config.numberOfGenerations;
		this.reportEvery = config.reportEvery;
		int size = (config.sequence.length() * 2) - 1;
		this.bestProtein = new Protein(config.dimensions, new Sequence(
				config.sequence), random, Grid.getInstance(size,
				config.dimensions), "best protain");
		gui = new RunningView("results", size, size);
		// guiGrid = new GUIGrid("Protein",size,size);
		// if (SHOW_BEST_IN_GUI)
		// {
		// this.bestguiGrid = new GUIGrid("best protein so far",size, size);
		// }
	}

	/**
	 * create new random population
	 * 
	 * @param runNumber
	 */
	public void initiate(int runNumber) {

		System.out.println("Initializing run # " + runNumber);
		setId("runNumber " + runNumber);

		population = new Population(config, random, mutationManager);
		population.sort();
		currentGenerarionNum = 0;
		if (isFirstInit) { // if this is the first init then create the needed
							// arrays else. clear the existing one's
			population.sort();
			// Collections.sort(population, Collections.reverseOrder());
			bestEnergy = new float[numberOfGenerations / reportEvery + 1];
			averageEnergy = new float[numberOfGenerations / reportEvery + 1];
			worstEnergy = new float[numberOfGenerations / reportEvery + 1];
			bestFitness = new float[numberOfGenerations / reportEvery + 1];
			averageFitness = new float[numberOfGenerations / reportEvery + 1];
			worstFitness = new float[numberOfGenerations / reportEvery + 1];
			fittest = new Conformation[numberOfGenerations / reportEvery + 1];
			generation = new int[numberOfGenerations / reportEvery + 1];
		}
		for (int i = 0; i < numberOfGenerations / config.reportEvery + 1; i++) {
			bestEnergy[i] = 0;
			averageEnergy[i] = 0;
			worstEnergy[i] = 0;
			bestFitness[i] = 0;
			averageFitness[i] = 0;
			worstFitness[i] = 0;
			fittest[i] = null;
		}
	}

	/**
	 * Gets the fitest.
	 * 
	 * @return the fitest
	 */
	public Conformation getFitestOfRun() {
		Conformation best = fittest[0];
		for (int i = 0; i < fittest.length; i++) {
			if (fittest[i] != null) {
				if (fittest[i].getFitness() > best.getFitness())
					best = fittest[i];
			}
		}
		return best;
	}

	/**
	 * Gets the best energy per generation array.
	 * 
	 * @return the best energy
	 */
	public float[] getBestEnergy() {
		return bestEnergy;
	}

	/**
	 * Gets the best fitness per generation array.
	 * 
	 * @return the best fitness
	 */
	public float[] getBestFitness() {
		return bestFitness;
	}

	/**
	 * Gets the average energy per generation array.
	 * 
	 * @return the average energy
	 */
	public float[] getAverageEnergy() {
		return averageEnergy;
	}

	/**
	 * Gets the average fitness per generation array.
	 * 
	 * @return the average fitness
	 */
	public float[] getAverageFitness() {
		return averageFitness;
	}

	/**
	 * Gets the worst energy per generation array.
	 * 
	 * @return the worst energy array
	 */
	public float[] getWorstEnergy() {
		return worstEnergy;
	}

	/**
	 * Gets the worst fitness per generation array.
	 * 
	 * @return the worst fitness array
	 */
	public float[] getWorstFitness() {
		return worstFitness;
	}

	/**
	 * Gets the fittest Of Generation array.
	 * 
	 * @return the fittest array
	 */
	public Conformation[] getFittest() {
		return fittest;
	}

	/**
	 * Gets the id of this Run.
	 * 
	 * @return the id
	 */
	public String getId() {
		return id;
	}

	/**
	 * Sets the id of the Run.
	 * 
	 * @param id
	 *            the new id
	 */
	public void setId(String id) {
		this.id = id;
	}

	public abstract void execute();
}
